package repo

import (
	"context"
	"forum/internal/adapter/driving/dao"
	"forum/internal/domain"
	"forum/internal/domain/cache"
	"forum/internal/domain/repo"
	"forum/internal/domain/vo"
	"time"
)

var _ repo.ArticleRepository = &ArticleRepositoryImp{}

type ArticleRepositoryImp struct {
	articleDao dao.ArticleDao
	client     cache.ArticleCache
}

func NewArticleRepositoryImp(articleDao dao.ArticleDao, articleCacheClient cache.ArticleCache) *ArticleRepositoryImp {
	return &ArticleRepositoryImp{
		articleDao: articleDao,
		client:     articleCacheClient,
	}
}

func (a *ArticleRepositoryImp) ListPub(ctx context.Context) ([]int64, error) {
	//TODO implement me
	panic("批量获取数据")
}

func (a *ArticleRepositoryImp) GetPubArticleById(ctx context.Context, id int64) (domain.Article, error) {
	pub, err := a.client.GetPub(ctx, id)
	if err == nil {
		return pub, err
	}
	return a.articleDao.GetPubById(ctx, id)
}

func (a *ArticleRepositoryImp) GetById(ctx context.Context, id int64) (domain.Article, error) {
	//查缓存
	art, err := a.client.Get(ctx, id)
	if err == nil {
		return art, err
	}
	return a.articleDao.GetByAuthorId(ctx, id)
}

func (a *ArticleRepositoryImp) SyncCache(ctx context.Context, art domain.Article) {
	go func() {
		cErr := a.client.Set(ctx, art)
		if cErr != nil {
			return
		}
	}()
}

func (a *ArticleRepositoryImp) GetAllByAuthorId(ctx context.Context, id int64, cursor vo.Page) ([]domain.Article, error) {
	if cursor.Offset == 0 && cursor.Limit == 100 {
		page, err := a.client.GetFirstPage(ctx, id)
		if err != nil {
			//log
			goto next
		}
		return page, nil
	}
	//next
next:
	list, err := a.articleDao.GetAllByAuthorId(ctx, id, cursor)
	if err != nil {
		return nil, err
	}
	//异步回写缓存
	go func() {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		if cursor.Offset == 0 && cursor.Limit == 100 {
			// 缓存回写失败，不一定是大问题，但有可能是大问题
			err = a.client.SetFirstPage(ctx, id, list)
			if err != nil {
				// 记录日志
				// 我需要监控这里
			}
		}
	}()

	return list, err
}

func (a *ArticleRepositoryImp) Sync(ctx context.Context, uid int64, article domain.Article) (int64, error) {
	id, err := a.articleDao.Sync(ctx, article)
	if err == nil {
		cErr := a.client.RemoveFirstPage(ctx, uid)
		if cErr != nil {
			//log
		}
	}
	go func() {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		cErr := a.client.SetPub(ctx, article)
		if cErr != nil {
			//log
		}
	}()
	return id, err
}

func (a *ArticleRepositoryImp) Update(ctx context.Context, uid int64, article domain.Article) error {
	err := a.articleDao.Update(ctx, article)
	if err == nil {
		cErr := a.client.RemoveFirstPage(ctx, uid)
		if cErr != nil {
			//log
		}
	}
	return err
}

func (a *ArticleRepositoryImp) Save(ctx context.Context, uid int64, article domain.Article) (int64, error) {
	art, err := a.articleDao.Insert(ctx, article)
	if err == nil {
		cErr := a.client.RemoveFirstPage(ctx, uid)
		if cErr != nil {
			//log
		}
	}
	return art, err
}
